package lv.solcraft.replication.server.api;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import lv.solcraft.replication.server.bdb.Database;
import lv.solcraft.replication.server.bdb.TxTemplate;
import lv.solcraft.replication.server.dao.OperDataAccess;
import lv.solcraft.replication.server.dao.OperSiteDataAccessFactory;
import lv.solcraft.replication.server.model.Oper;
import lv.solcraft.replication.server.model.OperSite;
import lv.solcraft.replication.server.model.OperState;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Transaction;
import com.sleepycat.persist.EntityCursor;

@Service
public class NewOpersCommand {

	private static final Logger log = Logger.getLogger(NewOpersCommand.class);
	
    private final Database database;
    private OperDataAccess operDataAccess;
    private OperSiteDataAccessFactory operSiteDataAccessFactory;

    @Autowired
    public NewOpersCommand(Database database) {
        this.database = database;
        this.operDataAccess = database.getOperDataAccess();
        this.operSiteDataAccessFactory = database.getOperSiteDataAccessFactory();
    }

    private List<Oper> getFirstNewOpers(final long siteId, final int batchSize) throws DatabaseException {
        List<Oper> opers = new ArrayList<Oper>();
        EntityCursor<OperSite> cursor = operSiteDataAccessFactory.newOpers(siteId).cursor();
        try {
            for (Iterator<OperSite> it = cursor.iterator(); it.hasNext() && opers.size() < batchSize;) {
                OperSite operSite = it.next();
                Oper oper = operDataAccess.find(operSite.getId());
        		if (oper == null) {
        			log.warn("Oper not found by id: " + operSite.getId() + ", removing oper site, siteId: " + siteId);
                    cursor.delete();
                    continue;
                }
                if (oper.recordHadErrors(siteId)) {
                    cursor.delete();
                    OperSite errorOperSite = oper.createOperSite(siteId, OperState.ERROR);
                    errorOperSite.setMessage("Record already had errors");
                    errorOperSite.persist();
                } else {
                    opers.add(oper);
                }
            }
            return opers;
        } finally {
            cursor.close();
        }
    }

    public List<Oper> getOpers(final long siteId, final int batchSize) {
        return new TxTemplate<List<Oper>>(database, 10) {
            @Override
            protected List<Oper> executeInTx(Transaction tx) throws Exception {
                return getFirstNewOpers(siteId, batchSize);
            }
        }.execute();
    }
}
